package app.species;

import java.awt.Color;
import java.awt.geom.Dimension2D;

import sim.engine.*;
import sim.portrayal.LocationWrapper;
import sim.util.*;

public class MovingFood extends Entity {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1028034672682203302L;

	private static double DEFAULT_RAND_VECT_LEN;

	@Parameter(name = "MOVINGFOOD_DEFAULT_DIAMETER")
	private static double DEFAULT_DIAMETER = 75.0;

	@Parameter(name = "MOVINGFOOD_DEFAULT_SENSE_DIST")
	private static double DEFAULT_SENSE_DIST = 75.0;

	@Parameter(name = "MOVINGFOOD_DEFAULT_SPEED")
	private static double DEFAULT_SPEED = 10.0;

	@Parameter(name = "MOVINGFOOD_DEFAULT_LIFE_SPAN")
	private static int DEFAULT_LIFE_SPAN = 0;

	@Parameter(name = "MOVINGFOOD_ENERGY")
	private static int energyAddedToCreature = 500;

	public MovingFood(MutableDouble2D initPos, MutableDouble2D initHead) {

		super(initPos, initHead);

		this.setDiameter(MovingFood.DEFAULT_DIAMETER);
		this.setSenseDistance(MovingFood.DEFAULT_SENSE_DIST);
		this.setSpeed(MovingFood.DEFAULT_SPEED);
		this.setLifeSpan(MovingFood.DEFAULT_LIFE_SPAN);
		this.resetColor();

		// WILL CHANGE!!!!!!
		this.setEnergy(MovingFood.energyAddedToCreature);

	}

	public MovingFood() {
		super();
	}

	public static void setDefaults(double diameter, double speed, double senseDist, int lifeSpan) {

		MovingFood.DEFAULT_DIAMETER = diameter;
		MovingFood.DEFAULT_SPEED = speed;
		MovingFood.DEFAULT_SENSE_DIST = senseDist;
		MovingFood.DEFAULT_LIFE_SPAN = lifeSpan;

	}

	// this gives the amount of randomness added to the final vector
	public static void setRandomVectorLength(double d) {

		MovingFood.DEFAULT_RAND_VECT_LEN = d;

	}

	public static void setEnergyAddedToCreature(int n) {
		MovingFood.energyAddedToCreature = n;
	}

	/*
	 * simply updates the agent's position based off of its heading and current
	 * position
	 */
	public void step(SimState state) {

		SpeciesSim sim = (SpeciesSim) state;

		if (this.getAge() > this.getLifeSpan()) {
			sim.removeEntityFromSim(this, sim.movingFood);
			return;
		}

		this.incrementAge();

		this.moveAwayFromCreatures(sim);

		// updates the heading of the entity if it is hitting a wall
		this.updateHeadingHitWall(sim.fieldWidth, sim.fieldHeight);

		/*
		 * update the position in the Continuous2D container also, update the
		 * position within the agent
		 */
		this.updatePosition();
		sim.movingFood.setObjectLocation(this, new Double2D(this.position));

	}

	/*
	 * moving food tries to avoid all creatures that it can currently see this
	 * updates the MovingFood's current heading
	 */
	private void moveAwayFromCreatures(SpeciesSim sim) {

		Bag nearbyCreatures = sim.creatures.getObjectsWithinDistance(new Double2D(this.position), 2*this.getSenseDistance());
		MutableDouble2D vectorAwayFromCreature = new MutableDouble2D();
		MutableDouble2D finalVector = new MutableDouble2D();
		MutableDouble2D randomVector;
		Creature creature;
		double dist;

		for (int i = 0; i < nearbyCreatures.numObjs; i++) {

			creature = (Creature) nearbyCreatures.objs[i];

			dist = this.position.distance(creature.position);

			assert(dist > 0.0);
			if (dist - creature.getRadius() <= this.getSenseDistance()) {

				vectorAwayFromCreature.subtract(this.position, creature.position);
				vectorAwayFromCreature.normalize();

				finalVector.addIn(vectorAwayFromCreature);

			}

		}

		this.heading = finalVector;

		if (finalVector.lengthSq() > 0.0) {

			// generate the random vector
			if (MovingFood.DEFAULT_RAND_VECT_LEN > 0.0) {

				while (true) {
					randomVector = new MutableDouble2D(sim.random.nextDouble() * MovingFood.DEFAULT_RAND_VECT_LEN,
							sim.random.nextDouble() * MovingFood.DEFAULT_RAND_VECT_LEN);

					if (randomVector.lengthSq() > 0.0 && randomVector.length() <= MovingFood.DEFAULT_RAND_VECT_LEN)
						break;

				}

				if (sim.random.nextBoolean())
					randomVector.x *= -1.0;
				if (sim.random.nextBoolean())
					randomVector.y *= -1.0;

				this.heading.normalize();

				this.heading.addIn(randomVector);

			}

			this.heading.normalize();
		}

	}

}
